using System;
using System.Reflection;
using System.Collections.Generic;
using System.Text;

namespace Ndo.Maths
{
    public class Arithmetic<TFinal> : Object<TFinal>, IArithmetic<TFinal>
        where TFinal : Arithmetic<TFinal>
    {
        protected Arithmetic() { }
        #region IArithmetic<TFinal> members
        public virtual TFinal Add(TFinal addend)
        {
            return OperatorDelegates<TFinal>.Addition(Self, addend);
        }

        public virtual TFinal SubtractedFrom(TFinal subtrahend)
        {
            return OperatorDelegates<TFinal>.Subtraction(Self, subtrahend);
        }

        public virtual TFinal MultipliedBy(TFinal multiplicator)
        {
            return OperatorDelegates<TFinal>.Multiply(Self, multiplicator);
        }

        public virtual TFinal DividedBy(TFinal divisor)
        {
            return OperatorDelegates<TFinal>.Division(Self, divisor);
        }
        #endregion

        #region IEquatable<TFinal> Members

        public virtual bool Equals(TFinal other)
        {
            return OperatorDelegates<TFinal>.Equality(Self, other);
        }

        #endregion

        public override bool Equals(object obj)
        {
            if (obj == null || obj.GetType() == typeof(TFinal))
                return false;
            return this.Equals((TFinal)obj);
        }


        #region IArithmetic members
        object IAddition.Add(object addend)
        {
            TFinal ret = (TFinal)addend;
            if(ret == null)
                return null;
            return this.Add(ret);
        }

        object ISubtraction.SubtractedFrom(object subtrahend)
        {
            TFinal ret = subtrahend as TFinal;
            if (ret == null)
                return null;
            return this.SubtractedFrom(ret);
        }

        object IMultiply.MultipliedBy(object multiplicator)
        {
            TFinal ret = multiplicator as TFinal;
            if (ret == null)
                return null;
            return this.MultipliedBy(ret);
        }

        object IDivision.DividedBy(object divisor)
        {
            TFinal ret = divisor as TFinal;
            if (ret == null)
                return null;
            return this.DividedBy(ret);
        }
        #endregion

        public TFinal GetSqr()
        {
            return Sqr(Self);
        }
        public static TFinal Sqr(TFinal v)
        {
            return v.MultipliedBy(v);
        }

    }
}
